home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Utilities / System / FKey / FKeys / dcl-ANSI (all) / dcl-ANSI.c < prev    next >
Text File  |  1993-04-22  |  11KB  |  461 lines

  1. /*
  2.  * dcl-ANSI.c
  3.  *
  4.  * By Jamie McCarthy, April 92.  This is public domain.
  5.  * If you have any questions or comments, you can reach me at
  6.  * “k044477@kzoo.edu” on the Internet, or at “j.mccarthy”
  7.  * on AppleLink.
  8.  *
  9.  * This code is based on a small program in Kernighan & Ritchie's
  10.  * “The C Programming Language,” 2nd ed., §5.12.  Yes, that's
  11.  * the famous “K&R,” the book that no C programmer should be
  12.  * without.  I changed a lot of stuff, enough that I feel
  13.  * comfortable about distributing this source (although I'm not
  14.  * a lawyer...sigh...)
  15.  *
  16.  * Yeah, I know, I know, the code's a mess.  It could probably
  17.  * be a helluva lot more elegant.  But it works.  Give me money,
  18.  * and I'll clean it up for you.  :-)
  19.  *
  20.  */
  21.  
  22.  
  23.  
  24. /******************************/
  25.  
  26. #include <ctype.h>
  27. #include <string.h>
  28.  
  29. #include "dcl-ANSI.h"
  30.  
  31. /******************************/
  32.  
  33.     /*
  34.      * Miscellaneous dcl-related variables and junk.
  35.      */
  36. enum {
  37.     kCStrTheVarNamed = kCStrLastErr + 1,
  38.     kCStrIsOfType,
  39.     kCStrEndOfSentence,
  40.     kCStrSpaceSeparator,
  41.     kCStrPointerTo,
  42.     kCStrFunction,
  43.     kCStrWithUndefdParams,
  44.     kCStrAcceptingParamsOfType,
  45.     kCStrCommaSeparator,
  46.     kCStrAnd,
  47.     kCStrReturningType,
  48.     kCStrArray,
  49.     kCStrOf,
  50.     kCStrAnErrorOccurred
  51. } ;
  52. OSErr gError;
  53. Handle gCDeclHndl;
  54. char *gCDeclPtr, *gCDeclEndPtr;
  55. #define getChar() (gCDeclPtr >= gCDeclEndPtr ? (++gCDeclPtr,'\0') : *gCDeclPtr++)
  56. #define ungetChar() (--gCDeclPtr)
  57. #define is_alpha(c) (isalpha(c) || (c) == '_')
  58. #define is_alnum(c) (isalnum(c) || (c) == '_')
  59. char gEnglish[1024];
  60. char gToken[100];
  61. char gName[100];
  62. char gDataType[7][100];
  63. short gDataTypeNo;
  64. short gTokenType; enum { kTTName=1, kTTSpecifier, kTTBrackets };
  65. enum { kLeftParen = '(', kRightParen = ')', kLeftBracket = '[', kRightBracket = ']' } ;
  66. Boolean gRequireIdentifier;
  67. Boolean gNextTypeIsBeingReturned;
  68. Boolean gNextTypeIsArrayElement;
  69.  
  70. /******************************/
  71.  
  72. void startupDcl(void);
  73. void scarfWhitespace(void);
  74. Boolean isSpecifier(char *s);
  75. char *englishCat(const char *suffix);
  76. void declarator(void);
  77. void dclANSI(void);
  78. void dirDcl(void);
  79. void funcProto(void);
  80. short getToken(void);
  81. void buildFinalString(void);
  82. void shutdownDcl(void);
  83.  
  84. /******************************/
  85.  
  86.  
  87.  
  88. void startupDcl(void)
  89. {
  90.     startupCStrs();
  91.     if (gError != noErr) return;
  92.     
  93.     HLock(gCDeclHndl);
  94.     gCDeclPtr = *gCDeclHndl;
  95.     gCDeclEndPtr = gCDeclPtr + GetHandleSize(gCDeclHndl);
  96.     gEnglish[0] = '\0';
  97.     gToken[0] = '\0';
  98.     gName[0] = '\0';
  99.     gDataType[0][0] = gDataType[1][0] = gDataType[2][0] =
  100.         gDataType[3][0] = gDataType[4][0] = gDataType[5][0] = gDataType[6][0] =
  101.         '\0';
  102.     gDataTypeNo = 0;
  103.     gRequireIdentifier = TRUE;
  104.     gNextTypeIsBeingReturned = FALSE;
  105.     gNextTypeIsArrayElement = FALSE;
  106.     getToken();
  107. }
  108.  
  109.  
  110.  
  111. char *englishCat(const char *suffix)
  112. {
  113.     if (gError != noErr
  114.         || strlen(gEnglish) + strlen(suffix) > sizeof(gEnglish) - 4) {
  115.         
  116.         if (gError == noErr) {
  117.             gError = kCStrEnglishTooLong;
  118.         }
  119.         return NULL;
  120.         
  121.     } else {
  122.         
  123.         return strcat(gEnglish, suffix);
  124.         
  125.     }
  126. }
  127.  
  128.  
  129.  
  130. void scarfWhitespace(void)
  131. {
  132.     char c;
  133.     do {
  134.         c = getChar();
  135.     } while (c != '\0' && isspace(c));
  136.     ungetChar();
  137. }
  138.  
  139.  
  140.  
  141. Boolean isSpecifier(char *s)
  142. {
  143.     short i, nSpecifiers;
  144.     nSpecifiers = getNSpecifiers();
  145.     for (i = 1; i <= nSpecifiers; ++i) {
  146.         if (!strcmp(s, getSpecifier(i))) {
  147.             return TRUE;
  148.         }
  149.     }
  150.     return FALSE;
  151. }
  152.  
  153.  
  154.  
  155. void declarator(void)
  156. {
  157.     if (gDataTypeNo >= 6) {
  158.         
  159.         gError = kCStrFuncProtosTooDeep;
  160.         
  161.     } else {
  162.         
  163.         gDataType[gDataTypeNo][0] = '\0';
  164.         while (gTokenType == kTTSpecifier) {
  165.             if (gDataType[gDataTypeNo][0] != '\0') {
  166.                 strcat(gDataType[gDataTypeNo], getMiscCStr(kCStrSpaceSeparator));
  167.             }
  168.             strcat(gDataType[gDataTypeNo], gToken);
  169.             getToken();
  170.         }
  171.         if (gDataType[gDataTypeNo][0] == '\0') {
  172.             gError = kCStrNoTypeSpecifier;
  173.         } else {
  174.             
  175.             ++gDataTypeNo;
  176.             dclANSI();
  177.             --gDataTypeNo;
  178.             
  179.             englishCat(gDataType[gDataTypeNo]);
  180.             
  181.         }
  182.         
  183.     }
  184. }
  185.  
  186.  
  187.  
  188. void dclANSI(void)
  189. {
  190.     short nStars = 0;
  191.     while (gError == noErr && gTokenType == '*') {
  192.         ++nStars;
  193.         getToken();
  194.     }
  195.     if (gError == noErr && gTokenType != '\0') {
  196.         dirDcl();
  197.     }
  198.     while (gError == noErr && nStars-- > 0) {
  199.         englishCat(getMiscCStr(kCStrPointerTo));
  200.         englishCat(getMiscCStr(kCStrSpaceSeparator));
  201.         gNextTypeIsBeingReturned = FALSE;
  202.         gNextTypeIsArrayElement = FALSE;
  203.     }
  204. }
  205.  
  206.  
  207.  
  208. void dirDcl(void)
  209. {
  210.     short type;
  211.     
  212.     if (gTokenType == kLeftParen) {
  213.         getToken();
  214.         if (gTokenType == kRightParen) {
  215.             if (gRequireIdentifier) {
  216.                 gError = kCStrExpectedIdentOrDCL;
  217.             } else {
  218.                 if (gNextTypeIsBeingReturned) {
  219.                     gError = kCStrFuncCantReturnFunc;
  220.                 } else if (gNextTypeIsArrayElement) {
  221.                     gError = kCStrArrayTypeCantBeFunc;
  222.                 } else {
  223.                     englishCat(getMiscCStr(kCStrFunction));
  224.                     englishCat(getMiscCStr(kCStrSpaceSeparator));
  225.                     englishCat(getMiscCStr(kCStrWithUndefdParams));
  226.                     englishCat(getMiscCStr(kCStrSpaceSeparator));
  227.                     englishCat(getMiscCStr(kCStrReturningType));
  228.                     englishCat(getMiscCStr(kCStrSpaceSeparator));
  229.                     gNextTypeIsBeingReturned = TRUE;
  230.                 }
  231.             }
  232.         } else {
  233.             if (gTokenType == kTTSpecifier && !gRequireIdentifier) {
  234.                 englishCat(getMiscCStr(kCStrFunction));
  235.                 englishCat(getMiscCStr(kCStrSpaceSeparator));
  236.                 englishCat(getMiscCStr(kCStrAcceptingParamsOfType));
  237.                 if (gError == noErr) {
  238.                     funcProto();
  239.                     if (gError == noErr) {
  240.                         englishCat(getMiscCStr(kCStrAnd));
  241.                         englishCat(getMiscCStr(kCStrSpaceSeparator));
  242.                         englishCat(getMiscCStr(kCStrReturningType));
  243.                         englishCat(getMiscCStr(kCStrSpaceSeparator));
  244.                         gNextTypeIsBeingReturned = TRUE;
  245.                     }
  246.                 }
  247.             } else {
  248.                 dclANSI();
  249.             }
  250.             if (gError == noErr && gTokenType != kRightParen) {
  251.                 gError = kCStrMissingRightParen;
  252.             }
  253.         }
  254.     } else if (gTokenType == kTTName) {
  255.         if (gName[0] == '\0') {
  256.                 // The only name we care about is that of the main declarator,
  257.                 // the first one found.
  258.             strcpy(gName, gToken);
  259.         }
  260.     } else if (!gRequireIdentifier && gTokenType == kTTBrackets) {
  261.         englishCat(getMiscCStr(kCStrArray));
  262.         englishCat(gToken);
  263.         englishCat(getMiscCStr(kCStrSpaceSeparator));
  264.         englishCat(getMiscCStr(kCStrOf));
  265.         englishCat(getMiscCStr(kCStrSpaceSeparator));
  266.         gNextTypeIsArrayElement = TRUE;
  267.     } else {
  268.         gError = kCStrExpectedIdentOrDCL;
  269.     }
  270.     while (gError == noErr && 
  271.         ((type = getToken()) == kTTBrackets
  272.         || type == kLeftParen)) {
  273.         
  274.         if (type == kLeftParen) {
  275.             if (gNextTypeIsBeingReturned) {
  276.                 gError = kCStrFuncCantReturnFunc;
  277.             } else if (gNextTypeIsArrayElement) {
  278.                 gError = kCStrArrayTypeCantBeFunc;
  279.             } else {
  280.                 englishCat(getMiscCStr(kCStrFunction));
  281.                 englishCat(getMiscCStr(kCStrSpaceSeparator));
  282.                 if (gError == noErr && (type=getToken()) == kRightParen) {
  283.                     englishCat(getMiscCStr(kCStrWithUndefdParams));
  284.                     englishCat(getMiscCStr(kCStrSpaceSeparator));
  285.                     englishCat(getMiscCStr(kCStrReturningType));
  286.                     englishCat(getMiscCStr(kCStrSpaceSeparator));
  287.                     gNextTypeIsBeingReturned = TRUE;
  288.                 } else {
  289.                     englishCat(getMiscCStr(kCStrAcceptingParamsOfType));
  290.                     if (gError == noErr) {
  291.                         funcProto();
  292.                         if (gError == noErr) {
  293.                             englishCat(getMiscCStr(kCStrAnd));
  294.                             englishCat(getMiscCStr(kCStrSpaceSeparator));
  295.                             englishCat(getMiscCStr(kCStrReturningType));
  296.                             englishCat(getMiscCStr(kCStrSpaceSeparator));
  297.                             gNextTypeIsBeingReturned = TRUE;
  298.                         }
  299.                     }
  300.                 }
  301.             }
  302.         } else {
  303.             if (gNextTypeIsBeingReturned) {
  304.                 gError = kCStrFuncCantReturnArray;
  305.             } else {
  306.                 englishCat(getMiscCStr(kCStrArray));
  307.                 englishCat(gToken);
  308.                 englishCat(getMiscCStr(kCStrSpaceSeparator));
  309.                 englishCat(getMiscCStr(kCStrOf));
  310.                 englishCat(getMiscCStr(kCStrSpaceSeparator));
  311.                 gNextTypeIsArrayElement = TRUE;
  312.             }
  313.         }
  314.         
  315.     }
  316.     
  317.     if (!gRequireIdentifier && gError == kCStrExpectedIdentOrDCL) {
  318.         gError = noErr;
  319.     }
  320. }
  321.  
  322.  
  323.  
  324. void funcProto(void)
  325. {
  326.     Boolean continueGettingArguments;
  327.     do {
  328.         gRequireIdentifier = FALSE;
  329.         declarator();
  330.         continueGettingArguments = (gError == noErr && gTokenType == ',');
  331.         if (continueGettingArguments) {
  332.             englishCat(getMiscCStr(kCStrCommaSeparator));
  333.             getToken();
  334.         }
  335.     } while (gError == noErr && continueGettingArguments);
  336.     gRequireIdentifier = TRUE;
  337.     if (gError == noErr && gTokenType != kRightParen) {
  338.         gError = kCStrMissingRightParen;
  339.     }
  340. }
  341.  
  342.  
  343.  
  344. short getToken(void)
  345. {
  346.     short c;
  347.     char *p = gToken;
  348.     
  349.     scarfWhitespace();
  350.     c = getChar();
  351.     if (c == ';') c = '\0';
  352.     if (c == kLeftParen) {
  353.         gTokenType = kLeftParen;
  354.     } else if (c == kLeftBracket) {
  355.         *p++ = c;
  356.         scarfWhitespace();
  357.         c = getChar();
  358.         if (is_alpha(c)) {
  359.             do {
  360.                 *p++ = c;
  361.             } while ( (c = getChar()) != '\0' && is_alnum(c) );
  362.         } else if (isdigit(c)) {
  363.             do {
  364.                 *p++ = c;
  365.             } while ( (c = getChar()) != '\0' && isdigit(c) );
  366.         }
  367.         ungetChar();
  368.         scarfWhitespace();
  369.         c = getChar();
  370.         if (c == kRightBracket) {
  371.             *p++ = c;
  372.             *p = '\0';
  373.             gTokenType = kTTBrackets;
  374.         } else {
  375.             gError = kCStrArraySyntaxError;
  376.         }
  377.     } else if (is_alpha(c)) {
  378.         *p++ = c;
  379.         while ((c=getChar()), (is_alnum(c) || c == ':')) {
  380.             *p++ = c;
  381.         }
  382.         *p = '\0';
  383.         ungetChar();
  384.         if (isSpecifier(gToken)) {
  385.             gTokenType = kTTSpecifier;
  386.         } else {
  387.             gTokenType = kTTName;
  388.         }
  389.     } else {
  390.         gTokenType = c;
  391.     }
  392.     return gTokenType;
  393. }
  394.  
  395.  
  396.  
  397. void buildFinalString(void)
  398. {
  399.         /*
  400.          * Put the whole string into gEnglish, which can be up to 1K long.
  401.          * This can involve swapping a lot of stuff around.
  402.          */
  403.     
  404.     if (gError == noErr && gTokenType != '\0') {
  405.         gError = kCStrSyntaxError;
  406.     }
  407.     if (gError < 0 || gError >= getNMiscCStrs()) {
  408.         unsigned char errNumStr[8];
  409.         strcpy(gEnglish, getMiscCStr(kCStrMacOSErrorOccurred));
  410.         NumToString(gError, errNumStr);
  411.         gError = 0;
  412.         englishCat(PtoCstr(errNumStr));
  413.         englishCat(getMiscCStr(kCStrPeriod));
  414.     } else if (gError == 0) {
  415.         short preEnglishLength, temp1, temp2;
  416.         preEnglishLength = strlen(getMiscCStr(kCStrTheVarNamed))
  417.             + strlen(gName)
  418.             + strlen(getMiscCStr(kCStrIsOfType));
  419.         if (gName[0] == '\0') {
  420.             gError = kCStrExpectedVarName;
  421.         } else if (preEnglishLength + strlen(gEnglish)
  422.             + strlen(getMiscCStr(kCStrEndOfSentence))
  423.             > sizeof(gEnglish)) {
  424.             gError = kCStrEnglishTooLong;
  425.         } else {
  426.             BlockMove(&gEnglish[0], &gEnglish[preEnglishLength], strlen(gEnglish)+1);
  427.             temp1 = strlen(getMiscCStr(kCStrTheVarNamed));
  428.             BlockMove(getMiscCStr(kCStrTheVarNamed), &gEnglish[0], temp1);
  429.             temp2 = strlen(gName);
  430.             BlockMove(&gName[0], &gEnglish[temp1], temp2);
  431.             temp1 += temp2;
  432.             temp2 = strlen(getMiscCStr(kCStrIsOfType));
  433.             BlockMove(getMiscCStr(kCStrIsOfType), &gEnglish[temp1], temp2);
  434.             englishCat(getMiscCStr(kCStrEndOfSentence));
  435.         }
  436.     }
  437.     if (gError > 0) {
  438.         strcpy(gEnglish, getMiscCStr(kCStrAnErrorOccurred));
  439.         strcat(gEnglish, getMiscCStr(gError));
  440.     }
  441.     
  442.     if (gError == 0) {
  443.         long secs;
  444.         DateTimeRec myDTR;
  445.         GetDateTime(&secs);
  446.         Secs2Date(secs, &myDTR);
  447.         if (myDTR.month == 4 && myDTR.day == 1) {
  448.             englishCat(" I think.");
  449.         }
  450.     }
  451. }
  452.  
  453.  
  454.  
  455. void shutdownDcl(void)
  456. {
  457.     DisposHandle(gCDeclHndl);
  458.     shutdownCStrs();
  459. }
  460.  
  461.